package com.cloud.tsp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cloud.api.domain.forward.VehicleForward;
import com.cloud.api.domain.model.VehicleModel;
import com.cloud.api.domain.screen.*;
import com.cloud.api.domain.stats.VehicleStats;
import com.cloud.api.domain.tsp.Command;
import com.cloud.api.domain.tsp.VehicleProduction;
import com.cloud.api.domain.tsp.VehicleSale;
import com.cloud.api.myenum.AlarmTypeEnum;
import com.cloud.tsp.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import jakarta.annotation.Resource;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service("screenService")
public class ScreenServiceImpl implements IScreenService {


    @Resource
    private IVehicleSaleService vehicleSaleService;
    @Resource
    private IVehicleMileageService vehicleMileageService;
    @Resource
    private IVehicleForwardService vehicleForwardService;
    @Resource
    private IVehicleProductionService vehicleProductionService;
    @Resource
    private ICommandService commandService;
    @Resource
    private ICommandExecHistoryService commandExecHistoryService;
    @Resource
    private IVehicleAlarmService vehicleAlarmService;
    @Resource
    private IVehicleMessageDailyService vehicleMessageDailyService;
    @Resource
    private IVehicleModelService vehicleModelService;
    @Resource
    private IModelPortraitService modelPortraitService;
    @Resource
    private IDeptExtendService deptExtendService;
    @Resource
    private IAlarmCategoryService alarmCategoryService;
    @Resource(name = "myRedis")
    private RedisTemplate<String, Object> redisTemplate;


    @Override
    public ScreenData getScreenData() {
        ScreenData screenData = (ScreenData) redisTemplate.opsForValue().get("screenData");
        if (screenData == null){
            screenData = selectScreenData();
        }
        return screenData;
    }

    public ScreenData selectScreenData(){
        Integer onlineToday = vehicleMessageDailyService.getOnlineToday();
        ScreenData screenData = new ScreenData();
        getVehicleAccess(screenData);
        getVehicleMileage(screenData);
        getOnlineRate(screenData);
        getModelMileage(screenData);
        getRealTimeAlarm(screenData);
        getIssueCommand(screenData);
        getFaultAlarm(screenData);
        getModelSale(screenData);
        getForwardData(screenData);
        screenData.setTodayOnlineCount(onlineToday);
        getSaleData(screenData);
        getSaleDept(screenData);
        Long cumulativeMileage = screenData.getVehicleAccess().getCumulativeMileage();
        screenData.setCumulativeCarbonReduction((int) (cumulativeMileage * 39.75 * (7.98+21) /100000)); //没有数据来源

        redisTemplate.opsForValue().set("screenData",screenData,Duration.ofMinutes(10));
        return screenData;
    }

    public void getVehicleAccess(ScreenData screenData){
        VehicleAccess vehicleAccess = new VehicleAccess();
        long saleCount = vehicleSaleService.count();
        Integer onlineCount = vehicleMessageDailyService.selectOnlineCountTotal();
        VehicleStatistics totalStatistics = vehicleMileageService.getTotalStatistics();
        vehicleAccess.setSaleVinCount((int)saleCount);
        vehicleAccess.setOnlineCount(onlineCount);
        vehicleAccess.setCumulativeChargePower(totalStatistics.getChargeCapacity());
        vehicleAccess.setCumulativeMileage(totalStatistics.getAccumulativeMileage());

        screenData.setVehicleAccess(vehicleAccess);
    }

    public void getVehicleMileage(ScreenData screenData){
        List<VehicleMileage> vehicleMileages = vehicleMileageService.getVehicleTop();
        screenData.setVehicleMileage(vehicleMileages);
    }

    public void getOnlineRate(ScreenData screenData){
        List<OnlineRate> onlineRates = new ArrayList<>();
        List<VehicleSale> saleCountTop10 = vehicleSaleService.getSaleCountTop10();
        List<VehicleSale> onlineVehicleModelCount = vehicleMessageDailyService.getOnlineVehicleModelCount();
        Map<String, Integer> modelCount = onlineVehicleModelCount.stream().collect(Collectors.toMap(VehicleSale::getModelType, VehicleSale::getSaleCount));
        for (VehicleSale vehicleSale : saleCountTop10){
            OnlineRate onlineRate = new OnlineRate();
            onlineRate.setModel(vehicleSale.getModelName());
            if (vehicleSale.getModelName() == null){
                onlineRate.setModel("未知");
            }
            onlineRate.setAccessVinCount(vehicleSale.getSaleCount());
            onlineRate.setOnlineVinCount(modelCount.getOrDefault(vehicleSale.getModelType(),0));
            double rate= (double)onlineRate.getOnlineVinCount()/onlineRate.getAccessVinCount();
            NumberFormat numberFormat  = NumberFormat.getPercentInstance();
            numberFormat.setMinimumFractionDigits(0);
            onlineRate.setRate(numberFormat.format(rate));
            onlineRates.add(onlineRate);
        }
        screenData.setOnlineRate(onlineRates);
    }

    public void getModelMileage(ScreenData screenData){
        List<ModelMileage> modelMileages = vehicleMileageService.getModelTop();
        if (modelMileages.isEmpty()){
            return;
        }
        double totalMileage = modelMileages.get(0).getAccumulatedMileage()/0.8;
        for (ModelMileage modelMileage : modelMileages){
            long percent = (long) (modelMileage.getAccumulatedMileage() * 100 / totalMileage);
            modelMileage.setPercent((int)percent);
        }
        screenData.setModelMileage(modelMileages);
    }

    public void getRealTimeAlarm(ScreenData screenData){
        List<RealTimeAlarm> realTimeAlarms = vehicleAlarmService.getRealAlarm();
        screenData.setRealTimeAlarm(realTimeAlarms);
    }

    public void getIssueCommand(ScreenData screenData){
        List<IssueCommand> issueCommands = new ArrayList<>();
        selectIssueCommand(issueCommands);
        screenData.setIssueCommand(issueCommands);
    }

    public void getFaultAlarm(ScreenData screenData){
        FaultAlarm faultAlarm = new FaultAlarm();
        long total = 0L;
        List<AlarmList> alarm = vehicleAlarmService.getFaultAlarm();
        Map<String, Integer> collect = alarm.stream().collect(Collectors.toMap(AlarmList::getName, AlarmList::getValue));
        for (AlarmList a : alarm){
            total += a.getValue();
        }
        faultAlarm.setTotal(total);
        int otherCount = (int) total;

        List<AlarmList> list = new ArrayList<>();
        for (AlarmTypeEnum typeEnum : AlarmTypeEnum.values()){
            AlarmList alarmList = new AlarmList();
            alarmList.setName(typeEnum.getDesc());
            alarmList.setValue(collect.getOrDefault(String.valueOf(typeEnum.getValue()),0));
            list.add(alarmList);
        }
        Collections.sort(list, new Comparator<AlarmList>() {
            @Override
            public int compare(AlarmList o1, AlarmList o2) {
                return Integer.compare(o2.getValue(), o1.getValue());
            }
        });

        List<AlarmList> returnList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            AlarmList alarmList = new AlarmList();
            BeanUtils.copyProperties(list.get(i), alarmList);
            otherCount -= list.get(i).getValue();
            returnList.add(alarmList);
        }
        AlarmList alarmList = new AlarmList();
        alarmList.setName("其他");
        alarmList.setValue(otherCount);
        returnList.add(alarmList);

        // 设置总数
        faultAlarm.setAlarmList(returnList);
        faultAlarm.setTotal(total);
        screenData.setFaultAlarm(faultAlarm);
    }

    public void getModelSale(ScreenData screenData){
        List<ModelSale> modelSales = vehicleSaleService.getSaleCountTop5();
        screenData.setModelSale(modelSales);
    }

    public void getForwardData(ScreenData screenData){
        ForwardData  forwardData = new ForwardData();
        selectForwardData(forwardData);
        screenData.setForwardData(forwardData);
    }

    public void getSaleData(ScreenData screenData){
        List<MapData> saleData = vehicleSaleService.getSaleCountMap();
        screenData.setSaleData(saleData);
    }

    public void getSaleDept(ScreenData screenData){
        List<MapData> saleDept = deptExtendService.getDeptCountMap();
        screenData.setSaleDept(saleDept);
    }




    @Override
    public HomeData getHomeData() {
        HomeData homeData = (HomeData) redisTemplate.opsForValue().get("homeData");
        if (homeData == null){
            homeData = selectHomeData();
        }
        return homeData;
    }

    public HomeData selectHomeData(){
        HomeData homeData = new HomeData();
        getVehicleType(homeData);
        getModelExcept1(homeData);
        getForwardData(homeData);
        getSaleRate(homeData);
        getIssueCommand(homeData);
        getVehicleMileage(homeData);
        getRealTimeAlarm(homeData);

        redisTemplate.opsForValue().set("homeData",homeData,Duration.ofMinutes(10));
        return homeData;
    }

    public void getVehicleType(HomeData homeData){
        List<VehicleType> vehicleTypes = new ArrayList<>();
        VehicleType evVehicle = new VehicleType();
        VehicleType oilVehicle = new VehicleType();
        VehicleDetail evVehicleDetail = new VehicleDetail();
        VehicleDetail oilVehicleDetail = new VehicleDetail();

        List<VehicleStatistics> list = vehicleMileageService.getTitleStatistics();
        list.forEach(a -> {
            if ("ev".equals(a.getVehicleType())){
                evVehicleDetail.setVehicleCount(a.getSaleCount());
                evVehicleDetail.setCumulativeMileage(a.getAccumulativeMileage());
                evVehicleDetail.setCumulativeChargePower(a.getChargeCapacity());
            }else {
                oilVehicleDetail.setVehicleCount(a.getSaleCount());
                oilVehicleDetail.setCumulativeMileage(a.getAccumulativeMileage());
                oilVehicleDetail.setCumulativeChargePower(a.getChargeCapacity());
            }
        });
        oilVehicleDetail.setVehicleCount(17083);
        oilVehicleDetail.setCumulativeMileage(0L);
        oilVehicleDetail.setCumulativeChargePower(0L);

        List<VehicleStats> onlineVehicleTypeCount = vehicleMessageDailyService.getOnlineVehicleTypeCount();
        Map<String, Long> collect = onlineVehicleTypeCount.stream().collect(Collectors.toMap(VehicleStats::getType, VehicleStats::getTotal));
        evVehicleDetail.setOnlineCount(collect.get("ev") != null ? collect.get("ev").intValue() : 0);
        oilVehicleDetail.setOnlineCount(collect.get("oil") != null ? collect.get("oil").intValue() : 0);
        oilVehicleDetail.setOnlineCount(0);

        evVehicle.setType("ev");
        evVehicle.setDetail(evVehicleDetail);
        vehicleTypes.add(evVehicle);
        oilVehicle.setType("oil");
        oilVehicle.setDetail(oilVehicleDetail);
        vehicleTypes.add(oilVehicle);
        homeData.setVehicleType(vehicleTypes);
    }

    public void getModelExcept1(HomeData homeData){
        Object o = redisTemplate.opsForValue().get("Vehicle:alarm");
        homeData.setModelExcept(o != null ? (List<ModelExcept>) o : new ArrayList<>());
    }

    public void getModelExcept(HomeData homeData){
//        List<AlarmCategory> list = alarmCategoryService.list();
//        Map<String, List<AlarmCategory>> categoryMap = list.stream().collect(Collectors.groupingBy(AlarmCategory::getCode));
        //车型画像图片
        List<ModelPortrait> modelPortraits = modelPortraitService.list();
        List<VehicleModel> modelList = vehicleModelService.getLastModelList();
        List<VehicleBreakdown> vehicleBreakdowns = vehicleAlarmService.selectBreakdowns();
        List<com.cloud.api.domain.tsp.VehicleMileage> vehicleMileage = vehicleMileageService.getVehicleMileage();

        Map<String, Map<String, List<VehicleBreakdown>>> groupedByModelIdAndCode = vehicleBreakdowns.stream()
                .collect(Collectors.groupingBy(VehicleBreakdown::getModelId,
                        Collectors.groupingBy(VehicleBreakdown::getCode)));
        Map<String, List<com.cloud.api.domain.tsp.VehicleMileage>> collect = vehicleMileage.stream()
                .filter(v -> v.getModelId() != null)
                .collect(Collectors.groupingBy(com.cloud.api.domain.tsp.VehicleMileage::getModelId));
        Map<String, List<ModelPortrait>> portraitMap = modelPortraits.stream().collect(Collectors.groupingBy(ModelPortrait::getModeId));

        List<ModelExcept> modelExcepts = new ArrayList<>();
        for (VehicleModel vehicleModel : modelList){
            ModelExcept modelExcept = new ModelExcept();
            modelExcept.setModelId(vehicleModel.getId());
            modelExcept.setModelName(vehicleModel.getModelName());
            List<ModelPortrait> modelPortrait = portraitMap.get(vehicleModel.getId());
            if (modelPortrait == null){
                //TODO 后期如果每个车型都有自己的图片需要修改为自己的，而不是统一的
                modelExcept.setPicUrl(modelPortraits.getFirst().getPicUrl());
                modelExcept.setItemConnectLine(modelPortraits.getFirst().getItemConnectLine());
            }else {
                ModelPortrait data = modelPortrait.get(0);
                modelExcept.setPicUrl(data.getPicUrl());
                modelExcept.setItemConnectLine(data.getItemConnectLine());
            }

            List<com.cloud.api.domain.tsp.VehicleMileage> modelMileage = collect.get(vehicleModel.getId());
            if (modelMileage == null){
                modelExcept.setAccumulativeMileage(0L);
                modelExcept.setCumulativeChargePower(0L);
                modelExcept.setRunTime(0L);
            }
            else {
                com.cloud.api.domain.tsp.VehicleMileage data = modelMileage.get(0);
                modelExcept.setAccumulativeMileage(data.getAccumulativeMileage());
                modelExcept.setCumulativeChargePower(data.getChargeCapacity());
                modelExcept.setRunTime(data.getRunTime());
            }
            Map<String, List<VehicleBreakdown>> codeBreaks = groupedByModelIdAndCode.get(vehicleModel.getId());
            List<VehicleBreakdown> breakdownList = new ArrayList<>();
            if (codeBreaks == null){
                for (int i = 1; i <= 19; i++) {
                    VehicleBreakdown vehicleBreakdown = new VehicleBreakdown();
                    vehicleBreakdown.setCode(String.valueOf(i));
                    vehicleBreakdown.setBreakCount(0L);
//                    List<AlarmCategory> alarmCategories = categoryMap.get(String.valueOf(i));
                    vehicleBreakdown.setName(AlarmTypeEnum.getDesc(i));
                    breakdownList.add(vehicleBreakdown);
                }
            }else {
                for (AlarmTypeEnum alarmTypeEnum : AlarmTypeEnum.values()){
                    Integer code = alarmTypeEnum.getValue();
                    VehicleBreakdown vehicleBreakdown = new VehicleBreakdown();
                    List<VehicleBreakdown> codeBreak = codeBreaks.get(String.valueOf(code));
                    vehicleBreakdown.setCode(String.valueOf(code));
                    vehicleBreakdown.setName(AlarmTypeEnum.getDesc(code));
                    if (codeBreak == null){
                        vehicleBreakdown.setBreakCount(0L);
                        breakdownList.add(vehicleBreakdown);
                        continue;
                    }
                    vehicleBreakdown.setBreakCount(codeBreak.get(0).getBreakCount());
                    breakdownList.add(vehicleBreakdown);
                }
            }
            modelExcept.setExceptCount(breakdownList);
            modelExcepts.add(modelExcept);
        }
        //给报警数据排序
        homeData.setModelExcept(orderException(modelExcepts,vehicleBreakdowns));

    }

    public List<ModelExcept> orderException(List<ModelExcept> modelExcepts, List<VehicleBreakdown>vehicleBreakdowns){
        List<ModelExcept> newModelExcepts = new ArrayList<>();

        Map<String, ModelExcept> collect = modelExcepts.stream().collect(Collectors.toMap(ModelExcept::getModelId, Function.identity()));
        // 按照 modelid 分组，并统计每个 modelid 对应的 count 字段的总和
        Map<String, Long> breakdownCountSumByModelId = vehicleBreakdowns.stream()
                .collect(Collectors.groupingBy(
                        VehicleBreakdown::getModelId,   // 分组依据
                        Collectors.summingLong(VehicleBreakdown::getBreakCount)  // 计算每个分组中 count 字段的总和
                ));
        // 将 Map 转换为 List 并按值（count 总和）降序排序
        List<Map.Entry<String, Long>> sortedEntries = breakdownCountSumByModelId.entrySet().stream()
                .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
                .toList();

        for (Map.Entry<String, Long> entry : sortedEntries) {
            ModelExcept modelExcept = collect.get(entry.getKey());
            if (modelExcept != null){
                newModelExcepts.add(modelExcept);
            }
            collect.remove(entry.getKey());
        }
        //由于并不是所有的车型都报警，所以需要把未报警的车型数据补充进去
        for (String key : collect.keySet()){
            ModelExcept modelExcept = collect.get(key);
            newModelExcepts.add(modelExcept);
        }
        return newModelExcepts;
    }

    public void getForwardData(HomeData homeData){
        ForwardData  forwardData = new ForwardData();
        selectForwardData(forwardData);
        homeData.setForwardData(forwardData);
    }

    public void selectForwardData(ForwardData  forwardData){
        List<String> dayList = getLastSevenDays();
        forwardData.setDateList(dayList);
        LocalDate endTime = LocalDate.now().minusDays(1);
        LocalDate startTime = LocalDate.now().minusDays(7);
        List<String> platNames = vehicleForwardService.selectPlatName(startTime, endTime);

        Map<String, List<Long> > recordMap = new HashMap<>();
        for (String platName : platNames) {
//            endTime = LocalDate.now().minusDays(1);
            startTime = LocalDate.now().minusDays(7);
            List<Long> platForwardCounts = new ArrayList<>();
            List<VehicleForward> vehicleForwards = vehicleForwardService.getForwardCount(platName);

            //使用map时过滤掉重复的key再执行接下来的操作
            Map<LocalDate, Long> dataCount = vehicleForwards.stream()
                    .collect(Collectors.toMap(
                            VehicleForward::getForwardDate,        // Key映射
                            VehicleForward::getForwardCount,       // Value映射
                            (existingValue, newValue) -> existingValue  // 合并函数：保留第一个值
                    ));

//            Map<LocalDate, Long> dataCount = vehicleForwards.stream().collect(Collectors.toMap(VehicleForward::getForwardDate, VehicleForward::getForwardCount));
            for (int i = 0; i < 7; i++) {
                platForwardCounts.add(dataCount.get(startTime) != null ? dataCount.get(startTime):0L);
                startTime = startTime.plusDays(1);
            }
            recordMap.put(platName,platForwardCounts);
        }
        forwardData.setPlatList(platNames);
        forwardData.setRecordMap(recordMap);

    }

    public List<String> getLastSevenDays() {
        List<String> dateList = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("MM.dd");
        Calendar calendar = Calendar.getInstance();

        for (int i = 0; i < 7; i++) {
            calendar.add(Calendar.DATE, -1);
            String dateStr = sdf.format(calendar.getTime());
            dateList.add(dateStr);
        }
        Collections.reverse(dateList);
        return dateList;
    }

    public void getSaleRate(HomeData homeData){
        List<SaleRate> saleRates = new ArrayList<>();
        List<String> model = vehicleProductionService.getProductionModel();
        List<VehicleProduction> productionCount = vehicleProductionService.getProductionCount();
        Map<String, Integer> productions = productionCount.stream().collect(Collectors.toMap(VehicleProduction::getModelName, VehicleProduction::getProductionCount));
        List<VehicleSale> saleCount = vehicleSaleService.getSaleCount();
        Map<String, Integer> sales = saleCount.stream().collect(Collectors.toMap(VehicleSale::getModelName, VehicleSale::getSaleCount));
        for (String proModel : model){
            SaleRate  saleRate = new SaleRate();
            saleRate.setModel(proModel);
            saleRate.setProductionCount(productions.get(proModel) != null ? productions.get(proModel):0);
            saleRate.setSaleCount(sales.get(proModel) != null ? sales.get(proModel):0);
            saleRates.add(saleRate);
        }
        homeData.setSaleRate(saleRates);
    }

    public void getIssueCommand(HomeData homeData){
        List<IssueCommand> issueCommands = new ArrayList<>();
        selectIssueCommand(issueCommands);
        homeData.setIssueCommand(issueCommands);
    }

    public void selectIssueCommand(List<IssueCommand> issueCommands){

        LambdaQueryWrapper<Command> queryCommand = new LambdaQueryWrapper<>();
        queryCommand.groupBy(Command::getControlGroup)
                .orderByAsc(Command::getControlGroup)
                .select(Command::getControlGroup);
        List<String> groupNames = commandService.selectCommands();
        List<Command> adminCommand = commandExecHistoryService.getCommandCount("admin");
        Map<String, Integer> adminMap = adminCommand.stream().collect(Collectors.toMap(Command::getControlGroup, Command::getCount));
        List<Command> phoneCommand = commandExecHistoryService.getCommandCount("phone");
        Map<String, Integer> phoneMap = phoneCommand.stream().collect(Collectors.toMap(Command::getControlGroup, Command::getCount));
        for (String command : groupNames){
            IssueCommand issueCommand = new IssueCommand();
            issueCommand.setCommandType(command);
            issueCommand.setAdminCount(adminMap.get(command) != null ? adminMap.get(command):0);
            issueCommand.setPhoneCount(phoneMap.get(command) != null ? phoneMap.get(command):0);
            issueCommands.add(issueCommand);
        }
    }

    public void getVehicleMileage(HomeData homeData){
        List<VehicleMileage> vehicleMileages = vehicleMileageService.getVehicleTop();
        homeData.setVehicleMileage(vehicleMileages);
    }

    public void getRealTimeAlarm(HomeData homeData){
        List<RealTimeAlarm> realTimeAlarms = vehicleAlarmService.getRealAlarm();
        homeData.setRealTimeAlarm(realTimeAlarms);
    }

}
